/*
 * SvrClient.cpp
 *
 *  Created on: 2012-7-11
 *      Author: ThinkPad
 */
#include "SvrClient.h"

SvrClient::SvrClient(void)
{
    count = 0;
    client_time_tick = 0;
    this->pSvrconfig = NULL;
    this->pSvrtask = NULL;
    this->pSvrlog = NULL;
}

SvrClient::~SvrClient(void)
{
    /*add your code here*/
}

/*
 * init server client
 */
int SvrClient::init(SvrConfig * pconfig,SvrTask * psvrtask,Svr_log * psvrlog,SvrFileManage * psvrfilemanage,int init_size)
{
    if(pconfig == NULL
    		||psvrtask == NULL
    		||psvrlog == NULL)
        return FAILURE;

    this->pSvrconfig = pconfig;
    this->pSvrtask = psvrtask;
    this->pSvrlog = psvrlog;
    this->pSvrFileUtils = psvrfilemanage;

    /*
    *alloc client token
    */
    for(int i = 0 ;i < init_size;i++)
    {
        user_token * token = NULL;
        token = new user_token();
        if(token != NULL)
        {
            client_pool.push(token);
            count++;
        }
    }

    return SUCCESS;
}

/*
*token pool operation
*/
void SvrClient::alloc(user_token ** client)
{
    pool_lock.Lock();
    {
        if(client_pool.size() >0 )
        {
             *client = client_pool.top();
             client_pool.pop();
        }
        else
        {
             *client = new user_token();
             count++;
        }
        /*init*/
        (*client)->tConnTime = time(NULL);
        (*client)->timeConnBegin = time(NULL);
        /*end*/
        pool_lock.Unlock();
    }
}

void SvrClient::free(user_token * client)
{
    pool_lock.Lock();
    {
        if(client != NULL)
        {
              client->id = 0;
              client->type = 0;
              client->index = 0;
              memset(client->key,'\0',sizeof(client->key));

              client->offset = 0;
              client->length = 0;
              client->count = 0;
              client->trans_size = 0;
              client->have_trans_size = 0;
              client->last_size = 0;

              if(client->filefd >= 0)
              {
                  close(client->filefd);
                  client->filefd = -1;
              }
              client->hFile_size = 0;
              client->hFile_offset = 0;

              client->send_timeout = 0;
              client->receive_timeout = 0;
              client->trans_file_timeout = 0;
              client->tConnTime = time(NULL);
              client->timeConnBegin = time(NULL);
              client->connectionFlag = 0;
              client->recv_send_flag = FALSE;
              client->conn_index = 0;
              client->privt = NULL;

              client_pool.push(client);
        }
        pool_lock.Unlock();
    }
}

int SvrClient::get_free_count()
{
    return (int)client_pool.size();
}

int SvrClient::get_count()
{
     return count;
}

/*
*alloc_request_header
*/
void SvrClient::alloc_request_header(http_request_header ** hrt)
{
    http_lock.Lock();
    {
        if(this->http_request_header_pool.size()>0)
        {
            *hrt = http_request_header_pool.top();
            http_request_header_pool.pop();
        }
        else
        {
            (*hrt) = new http_request_header();
        }
        http_lock.Unlock();
    }
}

/*
*free_request_header
*/
void SvrClient::free_request_header(http_request_header * hrt)
{
    http_lock.Lock();
    {
        if(hrt != NULL)
        {
            http_request_header_pool.push(hrt);
        }
        http_lock.Unlock();
    }
}

/*
*op buf alloc and free
*/
void SvrClient::alloc_op_buf(op_buf ** pbf)
{
    op_buf_lock.Lock();
    {
          if(this->op_buf_pool.size() > 0)
          {
              *pbf = op_buf_pool.top();
              op_buf_pool.pop();
          }
          else
          {
              *pbf = new op_buf();
              (*pbf)->buf = new ubyte[op_buf_len];
              (*pbf)->len = op_buf_len;
              memset((*pbf)->buf,'\0',op_buf_len);
          }
          op_buf_lock.Unlock();
    }
}

/*
*op buf alloc and free
*/
void SvrClient::free_op_buf(op_buf * pbf)
{
    op_buf_lock.Lock();
    {
        if(pbf != NULL)
        {
            memset(pbf->buf,'\0',op_buf_len);
            op_buf_pool.push(pbf);
        }
        op_buf_lock.Unlock();
    }
}

/*
*open request file
*/
bool SvrClient::open_request_file(http_request_header * hrt,user_token * token)
{
    if(strlen(this->pSvrconfig->rootpath) == 0 || hrt->file_name_len < 1)
    {
        pSvrlog->log_fmt(LOG_ERR,"root path or file_name is null");
        return false;
    }

    int retvalue  = false;
    /*transmit file name codes*/
    op_buf * m_src_code = NULL, * m_dest_code = NULL;
    this->alloc_op_buf(&m_src_code);
    this->alloc_op_buf(&m_dest_code);
    if(m_src_code == NULL || m_dest_code == NULL)
    {
        this->free_op_buf(m_src_code);
        this->free_op_buf(m_dest_code);
        m_src_code = NULL;
        m_dest_code = NULL;
        pSvrlog->log_fmt(LOG_ERR,"alloc op buf failure,open_request_file");
        return false;
    }

    /*get virtual path name */
	char * fptr = NULL;
	fptr = strstr(hrt->file_name + 1,"/");
	if(fptr != NULL)
	{
		m_src_code->len = fptr - hrt->file_name - 1;
		if(m_src_code->len > 0)
		{
			memcpy(m_src_code->buf,hrt->file_name + 1,m_src_code->len);
		}
	}
	/*get virtual direction*/
	bool ret = this->pSvrFileUtils->get_vir_dir((char *)m_src_code->buf,(char *)m_dest_code->buf,op_buf_len);
	/*get file name*/
	if(ret)
	{
		strcat((char *)m_dest_code->buf,fptr);
	}
	else
	{
		strcat((char *)m_dest_code->buf,hrt->file_name);
	}

    /*replace '\\' to '/' */
    size_t index = 0;
    size_t len = strlen((char *)m_dest_code->buf);
    while(index < len)
    {
        if((*(m_dest_code->buf+index)) == '\\')
                (*(m_dest_code->buf+index)) = '/';
        /*next char*/
        index++;
    }
    pSvrlog->log_fmt(LOG_INFO,"open file :%s\r\n",(char *)m_dest_code->buf);
    /*
    *open Linux file fd
    */
    token->filefd = this->pSvrFileUtils->open_file((char *)m_dest_code->buf,token->hFile_size);
    if(token->filefd >= 0 && token->hFile_size > 0)
    {
    	 retvalue = true;
    }

    /*free buf*/
    this->free_op_buf(m_src_code);
    this->free_op_buf(m_dest_code);
    m_src_code = NULL;
    m_dest_code = NULL;

    return retvalue;
}

/*
*decode file name
*/
bool SvrClient::decode_file_name(http_request_header * hrt,user_token * token)
{
    if(hrt == NULL || token == NULL)
         return false;

    /*begin check ,valid ,decode the filename*/
    unsigned int index = 0;
    char * pChar = _NULL;
    /*check is can decode*/
    pChar = strrchr(hrt->file_name,'.');
    if(pChar != NULL)
    {
        return false;
    }

    /*replace struct char to base64 char*/
    while(index <hrt->file_name_len)
    {
        if((*(hrt->file_name+index)) == '-')
                (*(hrt->file_name+index)) = '=';
        if((*(hrt->file_name+index)) == '^')
                (*(hrt->file_name+index)) = '/';
        if((*(hrt->file_name+index)) == '~')
                (*(hrt->file_name+index)) = '/';
        /*next char*/
        index++;
    }
    /*
    *now begin base64 decode
    */
    op_buf * m_src_code = NULL, * m_dest_code = NULL;
    this->alloc_op_buf(&m_src_code);
    this->alloc_op_buf(&m_dest_code);
    if(m_src_code == NULL || m_dest_code == NULL)
    {
        this->free_op_buf(m_src_code);
        this->free_op_buf(m_dest_code);
        m_src_code = NULL;
        m_dest_code = NULL;
        return false;
    }

    /*copy file name*/
    memcpy(m_src_code->buf,hrt->file_name,hrt->file_name_len);
    m_src_code->len = hrt->file_name_len;
    size_t ret_len =  utils::decode_base64(m_dest_code->buf,op_buf_len,m_src_code->buf,m_src_code->len);
    m_dest_code->len = ret_len;

    /*now begin url decode twice*/
    memset(m_src_code->buf,'\0',op_buf_len);
    m_src_code->len = 0;
    m_src_code->len = utils::url_decode(m_src_code->buf,op_buf_len,m_dest_code->buf,m_dest_code->len);

    memset(m_dest_code->buf,'\0',op_buf_len);
    m_dest_code->len = 0;
    m_dest_code->len = utils::url_decode(m_dest_code->buf,op_buf_len,m_src_code->buf,m_src_code->len);

    /*copy decode str to src args*/
    memset(hrt->file_name,'\0',hrt->file_name_len);
    memcpy(hrt->file_name,m_dest_code->buf,m_dest_code->len);

    /*free buf*/
    this->free_op_buf(m_src_code);
    this->free_op_buf(m_dest_code);
    m_src_code = NULL;
    m_dest_code = NULL;
    return true;

}

/*
*decode pars
*/
bool SvrClient::decode_pars(http_request_header * hrt,user_token * token)
{
    if(hrt == NULL || token == NULL)
        return false;

    bool ret =  false;
    /*get pars from file name*/
    if(hrt->pars_len == 0 && hrt->file_name_len > 64)
    {
        /*first,get pars*/
        char * ch_str = NULL;
        ch_str = strstr(hrt->file_name + 1,"/");
        if(ch_str != NULL)
        {
            hrt->pars_len = (size_t)(ch_str - hrt->file_name) - 1;
            if(hrt->pars_len > 0)
            {
                 memcpy(hrt->pars,hrt->file_name + 1 ,hrt->pars_len);
            }
        }
    }

    /*check pars format*/
    if(hrt->pars_len == 0)
    {
         return false;
    }

    /*replace struct char to base64 char*/
    unsigned int index = 0;
    while(index < hrt->pars_len)
    {
        if((*(hrt->pars+index)) == '-')
                (*(hrt->pars+index)) = '=';
        if((*(hrt->pars+index)) == '^')
                (*(hrt->pars+index)) = '/';
        if((*(hrt->pars+index)) == '~')
                       (*(hrt->pars+index)) = '/';
        /*next char*/
        index++;
    }
    /*now begin base64 decode*/
    op_buf * m_src_code = NULL, * m_dest_code = NULL;
    this->alloc_op_buf(&m_src_code);
    this->alloc_op_buf(&m_dest_code);
    if(m_src_code == NULL || m_dest_code == NULL)
    {
        this->free_op_buf(m_src_code);
        this->free_op_buf(m_dest_code);
        m_src_code = NULL;
        m_dest_code = NULL;
        return false;
    }

    /*copy pars*/
    memcpy(m_src_code->buf,hrt->pars,hrt->pars_len);
    m_src_code->len = hrt->pars_len;
    m_dest_code->len =  utils::decode_base64(m_dest_code->buf,op_buf_len,m_src_code->buf,m_src_code->len);

    /*get file name*/
    char * ch_str = NULL;
    ch_str = strstr((char *)m_dest_code->buf,"&file=");
    if(ch_str != NULL)
    {
        hrt->file_name_len =  m_dest_code->len - ((ubyte *)ch_str - m_dest_code->buf + 6);

        memset(hrt->file_name,'\0',MAX_REQ_PATH_LEN);
        memcpy(hrt->file_name,ch_str + 6,hrt->file_name_len);

        /*update pars*/
        m_dest_code->len -= 6 + hrt->file_name_len;
    }

    /*get session id*/
    ch_str = strstr((char *)m_dest_code->buf,"SessionID=");
    if(ch_str != NULL)
    {
        char * ch_end = NULL;
        ch_end =  strstr(ch_str,"&");
        if(ch_end != NULL)
        {
            size_t slen = ch_end - ch_str - 10;
            if(slen > 0  && slen < 64)
            {
                memcpy(token->key,ch_str + 10,slen);
                ret = true;
            }
        }
    }


    /*copy pars*/
    memset(hrt->pars,'\0',hrt->pars_len);
    memcpy(hrt->pars,m_dest_code->buf,m_dest_code->len);

    /*free buf*/
    this->free_op_buf(m_src_code);
    this->free_op_buf(m_dest_code);
    m_src_code = NULL;
    m_dest_code = NULL;

    /*return*/
    return ret;
}

/*
*decode administrator key
*/
bool SvrClient::decode_private_key(http_request_header * hrt)
{
    if(hrt == NULL)
          return false;

    if(hrt->privat_len == 0)
          return false;

    bool ret =  false;
    /*decode key*/
    op_buf * m_src_code = NULL, * m_dest_code = NULL;
    this->alloc_op_buf(&m_src_code);
    this->alloc_op_buf(&m_dest_code);
    if(m_src_code == NULL || m_dest_code == NULL)
    {
        this->free_op_buf(m_src_code);
        this->free_op_buf(m_dest_code);
        m_src_code = NULL;
        m_dest_code = NULL;
        return false;
    }

    /*replace struct char to base64 char*/
    unsigned int index = 0;
    while(index < hrt->privat_len)
    {
        if((*(hrt->privat+index)) == '-')
                (*(hrt->privat+index)) = '=';

        if((*(hrt->privat+index)) == '^')
                (*(hrt->privat+index)) = '/';

        if((*(hrt->privat+index)) == '~')
                (*(hrt->privat+index)) = '/';
        /*next char*/
        index++;
    }

    /*copy pars and base64 decode*/
    memcpy(m_src_code->buf,hrt->privat,hrt->privat_len);
    m_src_code->len = hrt->privat_len;
    m_dest_code->len =  utils::decode_base64(m_dest_code->buf,op_buf_len,m_src_code->buf,m_src_code->len);
    if(m_dest_code->len == 0)
    {
        this->free_op_buf(m_src_code);
        this->free_op_buf(m_dest_code);
        m_src_code = NULL;
        m_dest_code = NULL;
        return false;
    }

    /*3des decoder*/
    memset(m_src_code->buf,NULL,op_buf_len);
    m_src_code->len = des3_decrypt_default(m_dest_code->buf,m_dest_code->len,m_src_code->buf,op_buf_len);
    if(m_src_code->len == 0)
    {
	   this->free_op_buf(m_src_code);
	   this->free_op_buf(m_dest_code);
	   m_src_code = NULL;
	   m_dest_code = NULL;
	   return false;
    }
    /*str trim*/
    int count = 0;
    for(size_t i = m_src_code->len -1 ;i > 0 ; i--)
    {
        int code = m_src_code->buf[i];
        if(code <= 32 || code >= 127)
        {
            count ++;
        }
        else
        {
            break;
        }
    }
    m_src_code->len -= count;
    /*copy key*/
    if(m_src_code->len > 0)
    {
        memset(hrt->privat,'\0',hrt->privat_len);
        memcpy(hrt->privat,m_src_code->buf,m_src_code->len);
        hrt->privat_len = m_src_code->len;
        ret = true;
    }

    /*free buf*/
    this->free_op_buf(m_src_code);
    this->free_op_buf(m_dest_code);
    m_src_code = NULL;
    m_dest_code = NULL;

    /*return*/
    return ret;
}

/*
*encode key
*/
bool SvrClient::encode_private_key(char * data, size_t data_len,size_t max_buf_len)
{
	if(data == NULL)
		return false;

	if(data_len == 0)
		return false;

	if(max_buf_len < data_len)
		return false;

	bool ret = false;
	/*encode key*/
	op_buf * m_src_code = NULL, * m_dest_code = NULL;
	this->alloc_op_buf(&m_src_code);
	this->alloc_op_buf(&m_dest_code);
	if(m_src_code == NULL || m_dest_code == NULL)
	{
		this->free_op_buf(m_src_code);
		this->free_op_buf(m_dest_code);
		m_src_code = NULL;
		m_dest_code = NULL;
		return false;
	}

	/*init*/
	memcpy(m_src_code->buf,data,data_len);
	m_src_code->len = data_len;

	/*first 3des*/
	m_dest_code->len = des3_encrypt_default(m_src_code->buf,m_src_code->len,m_dest_code->buf,op_buf_len);
	if(m_dest_code->len == 0)
	{
		this->free_op_buf(m_src_code);
		this->free_op_buf(m_dest_code);
		m_src_code = NULL;
		m_dest_code = NULL;
		return false;
	}

	/*second base64*/
	memset(m_src_code->buf,NULL,op_buf_len);
	m_src_code->len = 0;
	m_src_code->len = utils::encode_base64(m_src_code->buf,op_buf_len,m_dest_code->buf,m_dest_code->len);
	if(m_src_code->len == 0)
	{
		this->free_op_buf(m_src_code);
		this->free_op_buf(m_dest_code);
		m_src_code = NULL;
		m_dest_code = NULL;
		return false;
	}
	else
	{
		/*replace struct char to base64 char*/
		size_t index = 0;
		while(index < m_src_code->len)
		{
			if((*(m_src_code->buf+index)) == '=')
				(*(m_src_code->buf+index)) = '-';

			if((*(m_src_code->buf+index)) == '/')
				(*(m_src_code->buf+index)) = '~';

			/*next char*/
			index++;
		}

		/*copy*/
		memset(data,'\0',max_buf_len);
		memcpy(data,m_src_code->buf,m_src_code->len);
	}

	/*free buf*/
	this->free_op_buf(m_src_code);
	this->free_op_buf(m_dest_code);
	m_src_code = NULL;
	m_dest_code = NULL;

	/*return*/
	return ret;
}

/*
*check administrator operation cmd args
*/
Client_Type SvrClient::administrator_op_cmd(http_request_header *hrt)
{
    if(hrt == NULL)
        return INVALID_TYPE;

    Client_Type ret_type = HTTP_ADMIN_CLIENT;
    if(decode_private_key(hrt))
    {
        /*get closefile cmd line*/
        if(hrt->privat_len > 6 && memcmp(hrt->privat,"clear:", 6) == 0)
        {
              //this->clear_client_connect_by_request_content(hrt->privat + 6);
        }
        else if(hrt->privat_len > 6 && memcmp(hrt->privat,"close:", 6) == 0)
        {
              //this->force_client_list_offline(hrt->privat + 6);
        }
        else if(hrt->privat_len > 6 && memcmp(hrt->privat,"login:", 6) == 0)
        {
             // ret_type =  SVR_ADMIN;
        }
    }
    else
    {
        ret_type =  HTTP_ADMIN_CLIENT;
    }

    return ret_type;
}

/**
 * set request content offset
 */
void SvrClient::set_request_content_offset(http_request_header * hrt,user_token * token)
{
	/*request rang*/
	if(hrt->content_offset >= token->hFile_size)
	{
		hrt->content_offset = (token->hFile_size - 1);
	}

	if(hrt->content_end  >= token->hFile_size)
	{
		hrt->content_end = (token->hFile_size -1);
	}

	if(hrt->content_offset > 0 || hrt->content_end > 0)
	{
		token->hFile_offset = hrt->content_offset;

		if(hrt->content_end < hrt->content_offset)
		{
			 hrt->content_end = (token->hFile_size - 1);
		}

		token->trans_size = (hrt->content_end - hrt->content_offset + 1);
	}
	else if(hrt->is_have_rang) /*some request ,rang:bytes=0-*/
	{
		token->trans_size = token->hFile_size;
	}

}

/*
*get request type
*/
Client_Type SvrClient::anylsis_client_type(char * buf,size_t buf_len,user_token * token)
{
    if(buf == NULL || buf_len == 0 ||  token == NULL)
       return INVALID_TYPE;

    int ret = FAILURE;
    Client_Type ret_type = INVALID_TYPE;
    http_request_header *hrt = NULL;
    this->alloc_request_header(&hrt);
    int parsecode = 0;
    ret = http::parse_request_header(hrt,buf,buf_len,parsecode);
    if(ret != SUCCESS)
    {
    	if(parsecode == 1 && hrt->method != UNKNOW)
    	{
    		this->free_request_header(hrt);
    		return ON_RECV_TYPE;
    	}

        this->pSvrlog->log_fmt(LOG_ERR,"Parse_Request_Header_Error:%s\r\n",buf);
        this->free_request_header(hrt);
        return INVALID_TYPE;
    }

    /*
     * check is receive completed
     */
    if(hrt->header_len == 0)
    {
       this->free_request_header(hrt);
       return ON_RECV_TYPE;
    }

    /*
    *check file name
    */
    if(hrt->mime == NONE && hrt->file_name_len > 0 &&  hrt->pars_len >0)
    {
        if(decode_file_name(hrt,token))
        {
             hrt->mime = http::anlysis_mime_type(hrt);
        }
    }

    /*
    *check request type
    */
    if(hrt->mime == XML)
	{
		token->type = HTTP_BROWSE;
		ret_type =  HTTP_BROWSE;
	}
    else if(hrt->mime == INFO)
    {
        ret_type = administrator_op_cmd(hrt);
        token->type = ret_type;
    }
    else if(hrt->mime == ASPNET)
    {
    	/*
		 * check is player client
		 */
		if(memcmp(hrt->file_name,"/auth.aspx",10) == 0)
		{

		}
		else if(memcmp(hrt->file_name,"/disauth.aspx",13) == 0)
		{
			/*add disauth client*/
		}
		else if(memcmp(hrt->file_name,"/heartbeat.aspx",15) == 0)
		{
			if(!decode_private_key(hrt))
			{
				 this->pSvrlog->log_fmt(LOG_ERR,"decode private data error:%s",hrt->privat);
				 token->type = INVALID_TYPE;
			}
			else
			{
				/*xMedia server is keepalive*/
				/**xLiveServer / xMediaServer**/
				/**heartbeat.aspx?type=xLiveServer&session_count=%d&connection_count=%d**/
				token->type = HTTP_BROWSE;
				/*add your code here*/
				this->pSvrlog->log_fmt(LOG_INFO,"server heartbeat url:%s!\r\n",hrt->path);
			}
		}
        ret_type =  (Client_Type)token->type;
    }

    /*must free http request vars*/
    this->free_request_header(hrt);
    return ret_type;
}

/*
 * run
 */
void SvrClient::run(void)
{

	 /*----run end---*/
	 this->client_time_tick ++;
}
